package me.minecraft.plugin.pokemontip.listener;

import com.cobblemon.mod.common.api.events.entity.SpawnEvent;
import com.cobblemon.mod.common.api.events.pokemon.PokemonCapturedEvent;
import com.cobblemon.mod.common.api.pokemon.stats.Stats;
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokeball.PokeBall;
import com.cobblemon.mod.common.pokemon.IVs;
import com.cobblemon.mod.common.pokemon.Pokemon;
import com.cobblemon.mod.common.pokemon.PokemonStats;
import com.cobblemon.mod.common.pokemon.Species;
import lg.minecraft.plugin.cobblemoncore.util.BukkitNmsConverter;
import lg.minecraft.plugin.cobblemoncore.util.PokemonPlaceholderReplacer;
import lg.minecraft.plugin.pokemonmenu.manager.DisplayPokemonManger;
import me.minecraft.plugin.pokemontip.PokemonTip;
import me.minecraft.plugin.pokemontip.PokemonType;
import me.minecraft.plugin.pokemontip.config.MainConfig;
import me.minecraft.plugin.pokemontip.config.PokemonTypeRecord;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.hover.content.Content;
import net.md_5.bungee.api.chat.hover.content.Text;
import net.minecraft.class_3222;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author langle__
 * @version 1.0
 */
public class CobblemonEvent {

    public static void onPokemonCaptured(PokemonCapturedEvent event) {
        MainConfig mainConfig = PokemonTip.getMainConfig();
        if (!mainConfig.isCaptureEnable()) return;
        class_3222 player = event.getPlayer();
        Pokemon pokemon = event.getPokemon();
        EmptyPokeBallEntity pokeBallEntity = event.getPokeBallEntity();

        Player bukkitPlayer = PokemonTip.toPlayer(player);
        Species species = pokemon.getSpecies();
        PokeBall pokeBall = pokeBallEntity.getPokeBall();
        PokemonType pokemonType = PokemonType.getPokemonType(pokemon);
        int ivsSum = getIvsSum(pokemon);

        World world = bukkitPlayer.getWorld();
        if (isWorldBlacklisted(world)) return;

        Map<Species, PokemonTypeRecord> spawnTypeMap = mainConfig.getSpawnTypeMap();
        PokemonTypeRecord pokemonTypeRecord = spawnTypeMap.get(species);

        if (pokemonTypeRecord == null) {
            if (pokemonType == PokemonType.normal) {
                if (!mainConfig.isCaptureNormal()) return;
                if (ivsSum < mainConfig.getCaptureIvNormal()) return;
            } else if (pokemonType == PokemonType.shiny_normal) {
                if (!mainConfig.isCaptureShinyNormal()) return;
                if (ivsSum < mainConfig.getCaptureIvShinyNormal()) return;
            } else if (pokemonType == PokemonType.mythical) {
                if (!mainConfig.isCaptureMythical()) return;
                if (ivsSum < mainConfig.getCaptureIvMythical()) return;
            } else if (pokemonType == PokemonType.shiny_mythical) {
                if (!mainConfig.isCaptureShinyMythical()) return;
                if (ivsSum < mainConfig.getCaptureIvShinyMythical()) return;
            } else if (pokemonType == PokemonType.ultra_beast) {
                if (!mainConfig.isCaptureUltraBeast()) return;
                if (ivsSum < mainConfig.getCaptureIvUltraBeast()) return;
            } else if (pokemonType == PokemonType.shiny_ultra_beast) {
                if (!mainConfig.isCaptureShinyUltraBeast()) return;
                if (ivsSum < mainConfig.getCaptureIvShinyUltraBeast()) return;
            } else if (pokemonType == PokemonType.legendary) {
                if (!mainConfig.isCaptureLegendary()) return;
                if (ivsSum < mainConfig.getCaptureIvLegendary()) return;
            } else if (pokemonType == PokemonType.shiny_legendary) {
                if (!mainConfig.isCaptureShinyLegendary()) return;
                if (ivsSum < mainConfig.getCaptureIvShinyLegendary()) return;
            } else if (pokemonType == PokemonType.paradox) {
                if (!mainConfig.isCaptureParadox()) return;
                if (ivsSum < mainConfig.getCaptureIvParadox()) return;
            } else if (pokemonType == PokemonType.shiny_paradox) {
                if (!mainConfig.isCaptureShinyParadox()) return;
                if (ivsSum < mainConfig.getCaptureIvShinyParadox()) return;
            }
        } else {
            if (ivsSum < pokemonTypeRecord.ivs()) return;
        }

        String pokemonTypeName = pokemonTypeRecord == null ? pokemonType.name() : pokemonTypeRecord.typeName();

        String message = mainConfig.getCaptureMessage()
                .replace("{player}", bukkitPlayer.getName())
                .replace("{poke_ball}", PokemonTip.getPokeBallName(pokeBall))
                .replace("{type}", pokemonTypeName);

        sendMessageWithPokemonInfo(pokemon, species, message);
    }

    public static void onPokemonEntitySpawn(SpawnEvent<PokemonEntity> event) {
        MainConfig mainConfig = PokemonTip.getMainConfig();
        PokemonEntity entity = event.getEntity();
        if (event.isCanceled()) return;
        if (!mainConfig.isSpawnEnable()) return;
        Entity bukkitEntity = BukkitNmsConverter.toEntity(entity);

        Pokemon pokemon = entity.getPokemon();
        Species species = pokemon.getSpecies();
        PokemonType pokemonType = PokemonType.getPokemonType(pokemon);
        Location location = bukkitEntity.getLocation();
        int ivsSum = getIvsSum(pokemon);

        World world = bukkitEntity.getWorld();
        if (isWorldBlacklisted(world)) return;

        Map<Species, PokemonTypeRecord> spawnTypeMap = mainConfig.getSpawnTypeMap();
        PokemonTypeRecord pokemonTypeRecord = spawnTypeMap.get(species);

        if (pokemonTypeRecord == null) {
            // 当没有配置自定义类型时，执行默认类型判断逻辑
            if (pokemonType == PokemonType.normal) {
                if (!mainConfig.isSpawnNormal()) return;
                if (ivsSum < mainConfig.getSpawnIvNormal()) return;
            } else if (pokemonType == PokemonType.shiny_normal) {
                if (!mainConfig.isSpawnShinyNormal()) return;
                if (ivsSum < mainConfig.getSpawnIvShinyNormal()) return;
            } else if (pokemonType == PokemonType.mythical) {
                if (!mainConfig.isSpawnMythical()) return;
                if (ivsSum < mainConfig.getSpawnIvMythical()) return;
            } else if (pokemonType == PokemonType.shiny_mythical) {
                if (!mainConfig.isSpawnShinyMythical()) return;
                if (ivsSum < mainConfig.getSpawnIvShinyMythical()) return;
            } else if (pokemonType == PokemonType.ultra_beast) {
                if (!mainConfig.isSpawnUltraBeast()) return;
                if (ivsSum < mainConfig.getSpawnIvUltraBeast()) return;
            } else if (pokemonType == PokemonType.shiny_ultra_beast) {
                if (!mainConfig.isSpawnShinyUltraBeast()) return;
                if (ivsSum < mainConfig.getSpawnIvShinyUltraBeast()) return;
            } else if (pokemonType == PokemonType.legendary) {
                if (!mainConfig.isSpawnLegendary()) return;
                if (ivsSum < mainConfig.getSpawnIvLegendary()) return;
            } else if (pokemonType == PokemonType.shiny_legendary) {
                if (!mainConfig.isSpawnShinyLegendary()) return;
                if (ivsSum < mainConfig.getSpawnIvShinyLegendary()) return;
            } else if (pokemonType == PokemonType.paradox) {
                if (!mainConfig.isSpawnParadox()) return;
                if (ivsSum < mainConfig.getSpawnIvParadox()) return;
            } else if (pokemonType == PokemonType.shiny_paradox) {
                if (!mainConfig.isSpawnShinyParadox()) return;
                if (ivsSum < mainConfig.getSpawnIvShinyParadox()) return;
            }
        } else {
            if (ivsSum < pokemonTypeRecord.ivs()) return;
        }

        String pokemonTypeName = pokemonTypeRecord == null ? pokemonType.name() : pokemonTypeRecord.typeName();
        Player player = getDistancePlayer(bukkitEntity, mainConfig.getSpawnRange());
        String playerName = player == null ? mainConfig.getUnknownPlayer() : player.getName();

        String message = mainConfig.getSpawnMessage()
                .replace("{type}", pokemonTypeName)
                .replace("{x}", String.valueOf(location.getBlockX()))
                .replace("{y}", String.valueOf(location.getBlockY()))
                .replace("{z}", String.valueOf(location.getBlockZ()))
                .replace("{player}", playerName);

        sendMessageWithPokemonInfo(pokemon, species, message);
    }


    private static void sendMessageWithPokemonInfo(Pokemon pokemon, Species species, String message) {
        MainConfig mainConfig = PokemonTip.getMainConfig();
        String[] parts = message.split("%pokemon% ", 2);
        TextComponent mainComponent = new TextComponent(parts[0]);
        TextComponent nameComponent = new TextComponent(mainConfig.getTextName().replace("{pokemon_name}", PokemonTip.getPokemonName(species)));
        TextComponent suffixComponent = new TextComponent(parts.length > 1 ? parts[1] : "");

        List<String> hover = mainConfig.getTextHover();
        Map<String, String> map = PokemonPlaceholderReplacer.buildPokemonInfoPlaceholders(pokemon);
        List<String> replacedHover = PokemonPlaceholderReplacer.replacePlaceholders(hover, map);

        List<Content> contents = new ArrayList<>();
        for (int i = 0; i < replacedHover.size(); i++) {
            String line = replacedHover.get(i);
            if (i + 1 == replacedHover.size()) {
                contents.add(new Text(line));
            } else  {
                contents.add(new Text(line + "\n"));
            }
        }

        nameComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, contents));
        long time = DisplayPokemonManger.INSTANCE.storePokemonWithTimestamp(new Pokemon[]{pokemon});
        nameComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/lgpm view " + time));

        mainComponent.addExtra(nameComponent);
        mainComponent.addExtra(suffixComponent);

        Bukkit.getOnlinePlayers().forEach(target -> target.spigot().sendMessage(mainComponent));
    }

    public static int getIvsSum(Pokemon pokemon) {
        int sum = 0;
        IVs ivs = pokemon.getIvs();
        if (getValue(ivs, Stats.HP) >= IVs.MAX_VALUE) {
            sum++;
        }
        if (getValue(ivs, Stats.SPEED) >= IVs.MAX_VALUE) {
            sum++;
        }
        if (getValue(ivs, Stats.ATTACK) >= IVs.MAX_VALUE) {
            sum++;
        }
        if (getValue(ivs, Stats.DEFENCE) >= IVs.MAX_VALUE) {
            sum++;
        }
        if (getValue(ivs, Stats.SPECIAL_ATTACK) >= IVs.MAX_VALUE) {
            sum++;
        }
        if (getValue(ivs, Stats.SPECIAL_DEFENCE) >= IVs.MAX_VALUE) {
            sum++;
        }
        return sum;
    }

    public static int getValue(PokemonStats pokemonStats, Stats stat) {
        Integer value = pokemonStats.get(stat);
        return value == null ? 0 : value;
    }

    public static Player getDistancePlayer(Entity entity, int distance) {
        for (Entity target : entity.getNearbyEntities(distance, distance, distance)) {
            if (target.getType() == EntityType.PLAYER) {
                return (Player) target;
            }
        }
        return null;
    }

    /**
     * 判断给定的世界是否存在于黑名单中
     *
     * @param world 需要检查的世界
     * @return 如果世界在黑名单中返回true，否则返回false
     */
    public static boolean isWorldBlacklisted(World world) {
        String worldName = world.getName();
        List<String> blackWorldList = PokemonTip.getMainConfig().getBlackWorldList();

        for (String blackWorld : blackWorldList) {
            if (worldName.equalsIgnoreCase(blackWorld)) {
                return true;
            }
        }

        return false;
    }


}